package com.wang.java.basic.features.reflect;

import com.wang.common.domain.ReflectUser;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 反射测试
 * 对于构造函数、属性、方法、注解而言，带Declare的方法能获取到所有的数据（包括private），不带的只能查到public的，如：
 * getField()
 * getFields()
 * getDeclaredField()
 * getDeclaredFields
 */
public class JavaReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<?> clazz = Class.forName("com.wang.common.domain.ReflectUser");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        System.out.println("所有的构造函数：");
        Arrays.stream(constructors).forEach(System.out::println);
        Field[] fields = clazz.getDeclaredFields();
        System.out.println("所有的属性：");
        Arrays.stream(fields).forEach(System.out::println);
        Method[] methods = clazz.getDeclaredMethods();
        System.out.println("所有的方法：");
        Arrays.stream(methods).forEach(System.out::println);
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        System.out.println("所有的注解：");
        Arrays.stream(annotations).forEach(System.out::println);
        /*
         * class.newInstance()默认使用无参构造函数初始化
         * 这里使用私有、有参构造函数初始化
          */
        Constructor<?> constructor = clazz.getDeclaredConstructor(int.class, String.class);
        constructor.setAccessible(true);// 设置私有构造函数可访问
        ReflectUser reflectUser = (ReflectUser) constructor.newInstance(1, "张三");
        System.out.println("反射使用私有、有参构造函数创建对象：" + reflectUser);
        /*
         * 反射访问私有属性
         */
        Field idField = clazz.getDeclaredField("id");
        idField.setAccessible(true);// 设置私有属性可访问
        int id = (int) idField.get(reflectUser);
        System.out.println("反射得到私有属性id：" + id);
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);// 设置私有属性可访问
        String name = (String) nameField.get(reflectUser);
        System.out.println("反射得到私有属性name：" + name);
        /*
         * 反射访问私有方法
         */
        Method method = clazz.getDeclaredMethod("privateMethod1", String.class, int.class);
        method.setAccessible(true);// 设置私有方法可访问
        String returnValue = (String) method.invoke(reflectUser, name, id);
        System.out.println("反射调用私有方法的返回值：" + returnValue);
    }
}
